#ifdef NKFM_KERNEL
#include <linux/spinlock_types.h>
#include <linux/types.h>
#include <linux/sched.h>
#endif

#define NKFM_DEBUG

#ifdef NKFM_KERNEL
#define NK_PRINT(...)	printk(__VA_ARGS__)
#else
#define NK_PRINT(...)	printf(__VA_ARGS__)
#endif	/*NKFM_KERNEL*/

#ifdef NKFM_DEBUG
#define nkfm_debug(...)	NK_PRINT( __VA_ARGS__)
#else
#define nkfm_debug(...)
#endif	/*NKFM_DEBUG*/

#define nkfm_print(...)	NK_PRINT(__VA_ARGS__)
#define nkfm_error(...)	NK_PRINT(__VA_ARGS__);
#define nkfm_info(...)	NK_PRINT(__VA_ARGS__);
#define nkfm_trace() NK_PRINT("%s %d\n", __FILE__, __LINE__)

#define NK_PRIVATE
#define NK_SHARED

#define NK_MAX_SKB_NODE_NR	(20480)
#define NK_MAX_RX_NODE_NR	(256)

#define NK_MAX_RX_Q_NR		(8)

#define NK_SKB_DATA_LEN		(2048)
#define NK_MAX_SEND_NR		(64)

#define NK_DEV_PATH		"/dev/nkfm"


#define NKFM_DEV_MAGIC	'K'
#define NK_CMD_GET_Q	_IO(NKFM_DEV_MAGIC, 0)
#define NK_CMD_PUT_Q	_IO(NKFM_DEV_MAGIC, 1)
#define NK_CMD_SHOW		_IO(NKFM_DEV_MAGIC, 2)
#define NK_CMD_CLEAR	_IO(NKFM_DEV_MAGIC, 3)


enum {
	NK_SKB_STATE_NONE,
	NK_SKB_STATE_PENDING,
	NK_SKB_STATE_DONE,
};

enum {
	NK_RX_Q_STATE_OFF,
	NK_RX_Q_STATE_ON,
};

enum {
	NK_SKB_POOL_KERNEL,
	NK_SKB_POOL_USER,
	NK_SKB_POOL_NR,
};

#ifdef NKFM_KERNEL
typedef spinlock_t nk_spinlock_t;
#else 
typedef int nk_spinlock_t;
#endif

struct nk_statistics_t {
	unsigned long long rcv;
	unsigned long long snd;
};

#if 0
struct nk_cmd_arg_t {
	int q_index;
	struct nk_statistics_t statistics;
};
#endif

struct nk_sk_buff_t {
	int index;
	int state;
	unsigned len;
	int next;
	char data[NK_SKB_DATA_LEN];
};

struct nk_skb_pool_t {
	int free;
	int rcv;
	int last;
#define NK_LOCK_PAD		32
	union {
		nk_spinlock_t lock;
		char pad[NK_LOCK_PAD];
	};
	union {
		nk_spinlock_t rcv_lock;
		char pad2[NK_LOCK_PAD];
	};
	struct nk_sk_buff_t n[NK_MAX_SKB_NODE_NR];
};

struct nk_rx_q_t {
	int pid;
	int state;
	int rcv;
	int pend;
	union {
		nk_spinlock_t lock;
		char pad[NK_LOCK_PAD];
	};
	int node[NK_MAX_RX_NODE_NR];
};


struct nk_mem_t {
	union {
		nk_spinlock_t lock;
		char pad[NK_LOCK_PAD];
	};
	struct nk_skb_pool_t pool[NK_SKB_POOL_NR];
	struct nk_rx_q_t rx_q[NK_MAX_RX_Q_NR];
};

/*************************************************************************/

#define NKFM_SKB_SIZE	2048

/*
 *
 */
struct nkfm_skb {
	unsigned short pindex;
	unsigned short index;
	unsigned char data[0];
};


struct nkfm_skb_pool {
	struct nkfm_skb_pool *next;
	unsigned short index;
	unsigned short order;
	unsigned short skb_nr;
	struct nkfm_skb *skbs;
	unsigned int len;
};


struct nkfm_cfg {
	unsigned int skb_nr;
};


/*************************************************************************/
static inline unsigned long long rdtsc(void)
{
	union {
		unsigned long long tsc_64;
		struct {
			unsigned int lo_32;
			unsigned int hi_32;
		};  
	} tsc;

	asm volatile("rdtsc" :
			"=a" (tsc.lo_32),
			"=d" (tsc.hi_32));

	return tsc.tsc_64;
}

/*************************************************************************/

#ifdef NKFM_KERNEL
extern struct nk_sk_buff_t* nk_alloc_skb(struct net_device *netdev, unsigned bufsz);
extern void nk_free_skb(struct nk_sk_buff_t *nk_skb);
extern int nk_receive_skb(struct nk_sk_buff_t *nk_skb);
#else
extern int nk_init(void);
extern void nk_show(void);
extern void nk_clear(void);
extern struct nk_sk_buff_t* nk_getwork(void);
extern void nk_send_skb(struct nk_sk_buff_t *nk_skb);




extern void nkfm_sched(int cpu);
#endif



